package scoping.blocks;

import ic.ast.decl.ClassType;
import ic.ast.decl.DeclClass;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import scoping.helpers.FaultyType.FaultType;
import scoping.helpers.ScopeException;

public class GlobalScope extends ScopeBlock {
	
	private static boolean hasMain;
	private HashMap<String, DeclClass> _classesMap;
	private DeclClass _libraryClass;
	private boolean _hasLibrary;
	
	public GlobalScope(List<DeclClass> classes) throws ScopeException{
		_classesMap = new HashMap<String, DeclClass>();
		hasMain = false;
		for (DeclClass declClass:classes)
		{
			if (TestAndSet(_variables, declClass.getName(), new ClassType(declClass.getLine(), declClass.getName())))
			{
				if (declClass.hasSuperClass())
				{
					if ((declClass.getSuperClassName().equals(declClass.getName())) 
							|| TestAndSet(_variables, declClass.getSuperClassName(), new ClassType(declClass.getLine(), declClass.getSuperClassName())))
					{
						throw new ScopeException(declClass.getLine(),String.format(FaultType.EXTENDS_NOT_FOUND.getDescription(),
								declClass.getName(),declClass.getSuperClassName()));
					}
				}
				_classesMap.put(declClass.getName(), declClass);
			}else
			{ 
				throw new ScopeException(declClass.getLine(),String.format(FaultType.DEFINED.getDescription(), declClass.getName()));
			}
		}
		_hasLibrary = false;
	}
	
	public GlobalScope(List<DeclClass> classes, DeclClass library) throws ScopeException{
		this(classes);
		_libraryClass = library;
		_variables.put(library.getName(), new ClassType(library.getLine(), library.getName()));
		_hasLibrary = true;
	}
	
	public boolean containsClass(String key){
		return _classesMap.containsKey(key) || (_hasLibrary || key.equals(_libraryClass.getName()));
	}
	
	public DeclClass getClass(String key){
		return _hasLibrary && key.equals(_libraryClass.getName()) ? _libraryClass : _classesMap.get(key);
	}
	
	public List<String> getClassNames(){
		List<String> classNames = new ArrayList<String>();
		for (DeclClass declClass:_classesMap.values()){
			classNames.add(declClass.getName());
		}
		return classNames;
	}
	
	public static boolean hasMain ()
	{
		return GlobalScope.hasMain;
	}
	
	public static void setHasMain()
	{
		GlobalScope.hasMain = true;
	}

	public boolean hasLibrary(){
		return this._hasLibrary;
	}
	
	public DeclClass getLibraryClass(){
		return this._libraryClass;
	}
}
